#pragma once
#include <brpc/server.h>

#include "base.pb.h"
#include "user.pb.h"
#include "file.pb.h"

#include "user-odb.hxx"

#include "etcd.hpp"
#include "channel.hpp"
#include "data_redis.hpp"
#include "data_es.hpp"
#include "mysql_user.hpp"
#include "utils.hpp"
#include "dms.hpp"


//短信服务暂时无法申请, dms模块相关无法实测
//GetPhoneVerifyCode
//PhoneRegister
//PhoneLogin
//SetUserPhoneNumber
class UserServiceImpl : public chat_system::UserService {
public:
    const static int MAX_NICKNAME_LENGTH = 20;
    const static int MAX_PASSWORD_LENGTH = 20;
    const static int MIN_PASSWORD_LENGTH = 6;
    const static int VERIFY_CODE_LENGTH = 4;
    using ptr = std::shared_ptr<UserServiceImpl>;



    UserServiceImpl(const std::shared_ptr<odb::core::database> &db
                    , const std::shared_ptr<sw::redis::Redis> &redis_client
                    , const std::shared_ptr<elasticlient::Client> &es_client
                    , const DMSClient::ptr &dms_client
                    , const ServiceManager::ptr &file_service_channel
                    , const std::string &file_service_name)
        : _user_table(std::make_shared<UserTable>(db)) 
        , _redis_session(std::make_shared<Session>(redis_client))
        , _redis_status(std::make_shared<Status>(redis_client))
        , _redis_codes(std::make_shared<Codes>(redis_client)) 
        , _es_client(std::make_shared<ESUser>(es_client))
        , _dms_client(dms_client)
        , _file_service_channel(file_service_channel)
        , _file_service_name(file_service_name) 
    {
        _file_service_channel->declared("file_service");
        _es_client->createIndex();
    }


    bool username_valid(const std::string& username) {
        return username.size() <= MAX_NICKNAME_LENGTH;
    }


    bool password_valid(const std::string& password) {
        if(password.size() < MIN_PASSWORD_LENGTH || password.size() > MAX_PASSWORD_LENGTH) {
            return false;
        }
        return true;
    }


    bool phone_valid(const std::string& phone) {
        if(phone.size() != 11) {
            return false;
        }
        if(phone[0] != '1') {
            return false;
        }
        if(phone[1] < '3' || phone[1] > '9') {
            return false;
        }
        for(char num : phone) {
            if(num < '0' || num > '9') {
                return false;
            }
        }
        return true;
    }


    bool verify_code_valid(const std::string& code) {
        if(code.size() != VERIFY_CODE_LENGTH) {
            return false;
        }
        for(char num : code) {
            if(num < '0' || num > '9') {
                return false;
            }
        }
        return true;
    }



    //用户名和密码注册
    virtual void UserRegister(google::protobuf::RpcController* controller,
                        const ::chat_system::UserRegisterReq* request,
                        ::chat_system::UserRegisterRsp* response,
                        ::google::protobuf::Closure* done)override {
        // 组织错误响应                           
        auto err_handle = [&response, &request](const std::string& err_msg)->void {
            response->set_request_id(request->request_id());
            response->set_success(false);
            response->set_errmsg(err_msg);
            LOG_ERROR("UserRegister失败: {}", err_msg);
        };


        brpc::ClosureGuard guard(done);
        std::string username = request->nickname();
        std::string password = request->password();

        // 检查用户名和密码的合法性
        if(!username_valid(username)) {
            err_handle("昵称长度超过限制");
            return;
        }
        if(!password_valid(password)) {
            err_handle("密码长度不合法");
            return;
        }

        // 检查用户名是否已存在
        auto user = _user_table->select_by_user_name(username);
        if(user) {
            err_handle("用户名已存在");
            LOG_ERROR(" {}", username);
            return;
        }

        // 向mysql中插入新用户
        std::string uid = uuid();
        user = std::make_shared<User>(uid, username, password);
        bool success = _user_table->insert(user);
        if(!success) {
            err_handle("插入用户到mysql失败");
            LOG_ERROR(" {}", username);
            return;
        }

        //向es中插入新用户
        success = _es_client->appendData(uid, username, "", "", "");
        if(!success) {
            err_handle("插入用户到es失败");
            LOG_ERROR(" {}", username);
            return;
        }

        //组织响应
        response->set_request_id(request->request_id());
        response->set_success(true);

        LOG_DEBUG("UserRegister 成功: {}", username);
    }


    virtual void UserLogin(google::protobuf::RpcController* controller,
                        const ::chat_system::UserLoginReq* request,
                        ::chat_system::UserLoginRsp* response,
                        ::google::protobuf::Closure* done)override {
        // 组织错误响应
        auto err_handle = [&response, &request](const std::string& err_msg)->void {
            response->set_request_id(request->request_id());
            response->set_success(false);
            response->set_errmsg(err_msg);
            LOG_ERROR("UserLogin 失败: {}", err_msg);
        };
        brpc::ClosureGuard guard(done);

        std::string username = request->nickname();
        std::string password = request->password();

        // 检查用户名和密码的匹配性
        auto user = _user_table->select_by_user_name(username);
        LOG_DEBUG("{} {}", user->user_name(), user->password());
        if(!user || user->password() != password) {
            err_handle("用户名或密码错误");
            LOG_ERROR(" {}", username);
            return;
        }

        // 判断是否已经登陆过
        // bool exist = _redis_status->exists(user->user_id());
        // if(exist) {
        //     err_handle("用户已登录");
        //     LOG_ERROR(" {}", username);
        //     return;
        // }

        // 为登录用户分配sessionid，记录进redis
        std::string session_id = uuid();
        bool success = _redis_session->append(session_id, user->user_id());
        if(!success) {
            err_handle("分配session失败");
            LOG_ERROR(" {}", username);
            return;
        }

        // 添加用户id到redis_status, 标记用户在线
        success = _redis_status->append(user->user_id());
        if(!success) {
            err_handle("标记用户在线失败");
            LOG_ERROR(" {}", username);
            return;
        }

        // 组织响应
        response->set_request_id(request->request_id());
        response->set_success(true);
        response->set_login_session_id(session_id);

        LOG_DEBUG("UserLogin 成功: {}", username);
    }


    virtual void GetPhoneVerifyCode(google::protobuf::RpcController* controller,
                        const ::chat_system::PhoneVerifyCodeReq* request,
                        ::chat_system::PhoneVerifyCodeRsp* response,
                        ::google::protobuf::Closure* done)override {
        // 组织错误响应
        auto err_handle = [&response, &request](const std::string& err_msg)->void {
            response->set_request_id(request->request_id());
            response->set_success(false);
            response->set_errmsg(err_msg);
            LOG_ERROR("GetPhoneVerifyCode 失败: {}", err_msg);
        };
        brpc::ClosureGuard guard(done);

        // 检查手机号的合法性
        std::string phone = request->phone_number();
        if(!phone_valid(phone)) {
            err_handle("手机号不合法");
            return;
        }
        
        // 生成4位验证码
        std::string code = verify_code(VERIFY_CODE_LENGTH);
        std::string code_id = uuid();

        // 将验证码存入redis
        bool success = _redis_codes->append(code_id, code);
        if(!success) {
            err_handle("存储验证码到redis失败");
            LOG_ERROR(" {}", phone);
            return;
        }
        // 发送验证码到手机
        success = _dms_client->send(phone, code);
        if(!success) {
            err_handle("发送验证码到手机失败");
            LOG_ERROR(" {}", phone);
            return;
        }

        // 组织响应
        response->set_request_id(request->request_id());
        response->set_success(true);
        response->set_verify_code_id(code_id);

        LOG_DEBUG("GetPhoneVerifyCode 成功: {}", phone);
    }


    virtual void PhoneRegister(google::protobuf::RpcController* controller,
                        const ::chat_system::PhoneRegisterReq* request,
                        ::chat_system::PhoneRegisterRsp* response,
                        ::google::protobuf::Closure* done)override {
        // 组织错误响应
        auto err_handle = [&response, &request](const std::string& err_msg)->void {
            response->set_request_id(request->request_id());
            response->set_success(false);
            response->set_errmsg(err_msg);
            LOG_ERROR("PhoneRegister 失败: {}", err_msg);
        };
        brpc::ClosureGuard guard(done);

        std::string phone = request->phone_number();
        std::string code_id = request->verify_code_id();
        std::string code = request->verify_code();

        // 检查手机号的合法性
        if(!phone_valid(phone)) {
            err_handle("手机号不合法");
            return;
        }

        // 检查验证码的合法性
        if(!verify_code_valid(code)) {
            err_handle("验证码不合法");
            return;
        }

        // 检查验证码是否与redis中存储的一致
        std::string redis_code;
        if(code != _redis_codes->code(code_id)) {
            err_handle("验证码不一致");
            LOG_ERROR(" {}", phone);
            return;
        }

        _redis_codes->remove(code_id); // 验证码使用后删除

        // 检查手机号是否已注册
        auto user = _user_table->select_by_phone(phone);
        if(user) {
            err_handle("手机号已注册");
            LOG_ERROR(" {}", phone);
            return;
        }
        
        // 向mysql中插入新用户
        std::string uid = uuid();

        user = std::make_shared<User>(uid, phone);
        bool success = _user_table->insert(user);
        if(!success) {
            err_handle("插入用户到mysql失败");
            LOG_ERROR(" {}", phone);
            return;
        }

        // 向es中插入新用户
        success = _es_client->appendData(uid, uid, phone, "", "");
        if(!success) {
            err_handle("插入用户到es失败");
            LOG_ERROR(" {}", phone);
            return;
        }

        // 组织响应
        response->set_request_id(request->request_id());
        response->set_success(true);
        LOG_DEBUG("PhoneRegister 成功: {}", phone);
    }


    virtual void PhoneLogin(google::protobuf::RpcController* controller,
                        const ::chat_system::PhoneLoginReq* request,
                        ::chat_system::PhoneLoginRsp* response,
                        ::google::protobuf::Closure* done)override {
        // 组织错误响应
        auto err_handle = [&response, &request](const std::string& err_msg)->void {
            response->set_request_id(request->request_id());
            response->set_success(false);
            response->set_errmsg(err_msg);
            LOG_ERROR("PhoneLogin 失败: {}", err_msg);
        };
        brpc::ClosureGuard guard(done);

        std::string phone = request->phone_number();
        std::string code_id = request->verify_code_id();
        std::string code = request->verify_code();

        // 检查手机号的合法性
        if(!phone_valid(phone)) {
            err_handle("手机号不合法");
            return;
        }

        // 检查验证码的合法性
        if(!verify_code_valid(code)) {
            err_handle("验证码不合法");
            return;
        }

        // 检查手机号是否已注册
        auto user = _user_table->select_by_phone(phone);
        if(!user) {
            err_handle("手机号未注册");
            LOG_ERROR(" {}", phone);
            return;
        }

        // 检查验证码是否与redis中存储的一致
        std::string redis_code;
        if(code != _redis_codes->code(code_id)) {
            err_handle("验证码不一致");
            LOG_ERROR(" {}", phone);
            return;
        }
        _redis_codes->remove(code_id); // 验证码使用后删除

        // 判断是否已经登陆过
        bool exist = _redis_status->exists(user->user_id());
        if(exist) {
            err_handle("用户已登录");
            LOG_ERROR(" {}", phone);
            return;
        }

        // 添加用户id到redis_status, 标记用户在线
        bool success = _redis_status->append(user->user_id());
        if(!success) {
            err_handle("标记用户在线失败");
            LOG_ERROR(" {}", phone);
            return;
        }

        // 为登录用户分配sessionid，记录进redis
        std::string session_id = uuid();
        success = _redis_session->append(session_id, user->user_id());
        if(!success) {
            err_handle("分配session失败");
            LOG_ERROR(" {}", phone);
            return;
        }


        //组织响应
        response->set_request_id(request->request_id());
        response->set_success(true);
        response->set_login_session_id(session_id);
        LOG_DEBUG("PhoneLogin 成功: {}", phone);
    }

    
    virtual void GetUserInfo(google::protobuf::RpcController* controller,
                        const ::chat_system::GetUserInfoReq* request,
                        ::chat_system::GetUserInfoRsp* response,
                        ::google::protobuf::Closure* done)override {
        // 组织错误响应
        auto err_handle = [&response, &request](const std::string& err_msg)->void {
            response->set_request_id(request->request_id());
            response->set_success(false);
            response->set_errmsg(err_msg);
            LOG_ERROR("GetUserInfo 失败: {}", err_msg);
        };
        brpc::ClosureGuard guard(done);

        std::string uid = request->user_id();
        if(uid.empty()) {
            err_handle("用户ID不能为空");
            return;
        }        

        // 从数据库查询信息 
        auto user = _user_table->select_by_id(uid);
        if(!user) {
            err_handle("用户不存在");
            LOG_ERROR(" {}", uid);
            return;
        }
        // 根据用户头像id向文件服务查询头像信息
        std::string avatar_id = user->avatar_id();
        //头像id为空可以直接返回了
        if(avatar_id.empty()) {
            response->set_request_id(request->request_id());
            response->set_success(true);
            response->mutable_user_info()->set_user_id(user->user_id());
            response->mutable_user_info()->set_nickname(user->user_name());
            response->mutable_user_info()->set_description(user->description());
            response->mutable_user_info()->set_phone(user->phone());
            return;
        }
        //获取文件服务信道管理对象
        auto channel_manager = _file_service_channel->choose(_file_service_name);
        if(channel_manager == nullptr) {
            err_handle("获取文件服务信道失败");
            return;
        }
        // 获取文件服务信道
        auto channel = channel_manager->choose();
        if(channel == nullptr) {
            err_handle("获取文件服务信道失败");
            return;
        }

        //向文件服务查询头像信息
        chat_system::FileService_Stub stub(channel.get());
        chat_system::GetSingleFileReq req;
        chat_system::GetSingleFileRsp rsp;
        req.set_request_id(request->request_id());
        req.set_file_id(avatar_id);
        brpc::Controller cntl;
        stub.GetSingleFile(&cntl, &req, &rsp, nullptr);
        if(cntl.Failed() || !rsp.success()) {
            err_handle("获取头像信息失败");
            LOG_ERROR(" {}", uid);
            return;
        }
        // 头像信息获取成功, 组织响应
        response->set_request_id(request->request_id());
        response->set_success(true);
        response->mutable_user_info()->set_user_id(user->user_id());
        response->mutable_user_info()->set_nickname(user->user_name());
        response->mutable_user_info()->set_description(user->description());
        response->mutable_user_info()->set_phone(user->phone());
        response->mutable_user_info()->set_avatar(rsp.file_data().file_content());
        LOG_DEBUG("GetUserInfo 成功: {}", uid);
    }


    virtual void GetMultiUserInfo(google::protobuf::RpcController* controller,
                        const ::chat_system::GetMultiUserInfoReq* request,
                        ::chat_system::GetMultiUserInfoRsp* response,
                        ::google::protobuf::Closure* done)override {
        // 组织错误响应
        auto err_handle = [&response, &request](const std::string& err_msg)->void {
            response->set_request_id(request->request_id());
            response->set_success(false);
            response->set_errmsg(err_msg);
            LOG_ERROR("GetMultiUserInfo 失败: {}", err_msg);
        };
        brpc::ClosureGuard guard(done);
        // 获取用户id列表
        int size = request->users_id_size();
        vector<std::string> uid_list(size);
        for(int i = 0; i < size; ++i) {
            LOG_DEBUG("{}---", request->users_id(i));
            uid_list[i] = request->users_id(i);
        }

        // 从数据库查询信息
        std::vector<User> users = _user_table->select_multi_users(uid_list);
        if(users.empty()) {
            err_handle("查询列表为空");
            return;
        }
        LOG_DEBUG("USER的头像ID {}", users.begin()->avatar_id());
        LOG_DEBUG("USER的ID {}", users.begin()->user_id());
        if(users.size() != size) {
            err_handle("部分用户不存在");
            return;
        }

        //获取文件服务信道管理对象
        auto channel_manager = _file_service_channel->choose(_file_service_name);
        if(channel_manager == nullptr) {
            err_handle("获取文件服务信道失败");
            return;
        }
        // 获取文件服务信道
        auto channel = channel_manager->choose();
        if(channel == nullptr) {
            err_handle("获取文件服务信道失败");
            return;
        }

        //向文件服务批量查询头像信息
        chat_system::FileService_Stub stub(channel.get());
        chat_system::GetMultiFileReq req;
        chat_system::GetMultiFileRsp rsp;
        req.set_request_id(request->request_id());
        // 添加头像id到请求中
        for(const auto& user : users) {
            std::string avatar_id = user.avatar_id();
            LOG_DEBUG("avatar_id: {}---", avatar_id);
            if(!avatar_id.empty()) {
                req.add_file_id_list(avatar_id);
            }
        }
        brpc::Controller cntl;
        stub.GetMultiFile(&cntl, &req, &rsp, nullptr);
        LOG_DEBUG("---{} {}---", cntl.Failed(), rsp.success());
        if(cntl.Failed() || !rsp.success()) {
            err_handle("获取头像信息失败");
            LOG_ERROR(" {} {}", rsp.errmsg(), cntl.ErrorText());
            return;
        }

        //组织响应
        response->set_request_id(request->request_id());
        response->set_success(true);
        auto p_user_info_map = response->mutable_users_info();
        auto& user_info_map = *p_user_info_map;
        auto p_file_data_map = rsp.mutable_file_data();
        auto& file_data_map = *p_file_data_map;
        for(auto& user : users) {
            chat_system::UserInfo user_info;
            user_info.set_user_id(user.user_id());
            user_info.set_nickname(user.user_name());
            user_info.set_description(user.description());
            user_info.set_phone(user.phone());
            user_info.set_avatar(file_data_map[user.avatar_id()].file_content());
            user_info_map[user.user_id()] = user_info;
        }

        LOG_DEBUG("GetMultiUserInfo 成功");
    }

    
    virtual void SetUserAvatar(google::protobuf::RpcController* controller,
                        const ::chat_system::SetUserAvatarReq* request,
                        ::chat_system::SetUserAvatarRsp* response,
                        ::google::protobuf::Closure* done)override {
        // 组织错误响应
        auto err_handle = [&response, &request](const std::string& err_msg)->void {
            response->set_request_id(request->request_id());
            response->set_success(false);
            response->set_errmsg(err_msg);
            LOG_ERROR("SetUserAvatar 失败: {}", err_msg);
        };
        brpc::ClosureGuard guard(done);

        std::string uid = request->user_id();
        if(uid.empty()) {
            err_handle("用户ID不能为空");
            return;
        }        

        auto user = _user_table->select_by_id(uid);
        if(!user) {
            err_handle("用户不存在");
            LOG_ERROR(" {}", uid);
            return;
        }

        //获取文件服务信道管理对象
        auto channel_manager = _file_service_channel->choose(_file_service_name);
        if(channel_manager == nullptr) {
            err_handle("获取文件服务信道失败");
            return;
        }
        // 获取文件服务信道
        auto channel = channel_manager->choose();
        if(channel == nullptr) {
            err_handle("获取文件服务信道失败");
            return;
        }

        // 向文件服务上传头像
        chat_system::FileService_Stub stub(channel.get());
        chat_system::PutSingleFileReq req;
        chat_system::PutSingleFileRsp rsp;
        req.set_request_id(request->request_id());
        req.mutable_file_data()->set_file_name("");
        req.mutable_file_data()->set_file_size(request->avatar().size());
        req.mutable_file_data()->set_file_content(request->avatar());

        brpc::Controller cntl;
        stub.PutSingleFile(&cntl, &req, &rsp, nullptr);
        if(cntl.Failed() || !rsp.success()) {
            err_handle("获取头像信息失败");
            return;
        }


        //头像上传成功, 头像id更新到数据库
        std::string avatar_id = rsp.file_info().file_id();
        user->set_avatar_id(avatar_id);
        bool success = _user_table->update(user);
        if(!success) {
            err_handle("更新用户头像到mysql失败");
            LOG_ERROR(" {}", uid);
            return;
        }


        //更新数据到es
        success = _es_client->appendData(uid, user->user_name(), user->phone(), user->description(), avatar_id);
        if(!success) {
            err_handle("更新用户头像到es失败");
            LOG_ERROR(" {}", uid);
            return;
        }

        //组织响应
        response->set_request_id(request->request_id());
        response->set_success(true);
        LOG_DEBUG("SetUserAvatar 成功: {}", uid);
    }


    virtual void SetUserNickname(google::protobuf::RpcController* controller,
                        const ::chat_system::SetUserNicknameReq* request,
                        ::chat_system::SetUserNicknameRsp* response,
                        ::google::protobuf::Closure* done)override {
        // 组织错误响应
        auto err_handle = [&response, &request](const std::string& err_msg)->void {
            response->set_request_id(request->request_id());
            response->set_success(false);
            response->set_errmsg(err_msg);
            LOG_ERROR("SetUserNickname 失败: {}", err_msg);
        };
        brpc::ClosureGuard guard(done);
        
        std::string uid = request->user_id();
        if(uid.empty()) {
            err_handle("用户ID不能为空");
            return;
        }        


        //检查昵称的合法性
        std::string new_user_name = request->nickname();
        if(!username_valid(new_user_name)) {
            err_handle("昵称长度超过限制");
            return;
        }

        //判断用户是否存在
        auto user = _user_table->select_by_id(uid);
        if(!user) {
            err_handle("用户不存在");
            LOG_ERROR(" {}", uid);
            return;
        }

        //判断新用户名是否存在
        auto exist_user = _user_table->select_by_user_name(new_user_name);
        if(exist_user && exist_user->user_id() != uid) {
            err_handle("用户名已存在");
            LOG_ERROR(" {}", new_user_name);
            return;
        }


        // 更新到数据库
        user->set_user_name(new_user_name);
        bool success = _user_table->update(user);
        if(!success) {
            err_handle("更新用户昵称到mysql失败");
            LOG_ERROR(" {}", uid);
            return;
        }


        // 更新到es
        success = _es_client->appendData(uid, new_user_name, user->phone(), user->description(), user->avatar_id());
        if(!success) {
            err_handle("更新用户昵称到es失败");
            LOG_ERROR(" {}", uid);
            return;
        }


        //组织响应
        response->set_request_id(request->request_id());
        response->set_success(true);
        LOG_DEBUG("SetUserNickname 成功: {}", uid);
    }


    virtual void SetUserDescription(google::protobuf::RpcController* controller,
                        const ::chat_system::SetUserDescriptionReq* request,
                        ::chat_system::SetUserDescriptionRsp* response,
                        ::google::protobuf::Closure* done)override {
        // 组织错误响应
        auto err_handle = [&response, &request](const std::string& err_msg)->void {
            response->set_request_id(request->request_id());
            response->set_success(false);
            response->set_errmsg(err_msg);
            LOG_ERROR("SetUserDescription 失败: {}", err_msg);
        };
        brpc::ClosureGuard guard(done);
        
        std::string uid = request->user_id();
        if(uid.empty()) {
            err_handle("用户ID不能为空");
            return;
        }        


        std::string new_desc = request->description();

        //判断用户是否存在
        auto user = _user_table->select_by_id(uid);
        if(!user) {
            err_handle("用户不存在");
            LOG_ERROR(" {}", uid);
            return;
        }


        // 更新到数据库
        user->set_description(new_desc);
        bool success = _user_table->update(user);
        if(!success) {
            err_handle("更新用户签名到mysql失败");
            LOG_ERROR(" {}", uid);
            return;
        }


        // 更新到es
        success = _es_client->appendData(uid, user->user_name(), user->phone(), new_desc, user->avatar_id());
        if(!success) {
            err_handle("更新用户签名到es失败");
            LOG_ERROR(" {}", uid);
            return;
        }


        //组织响应
        response->set_request_id(request->request_id());
        response->set_success(true);
        LOG_DEBUG("SetUserDescription 成功: {}", uid);

    }

    
    virtual void SetUserPhoneNumber(google::protobuf::RpcController* controller,
                        const ::chat_system::SetUserPhoneNumberReq* request,
                        ::chat_system::SetUserPhoneNumberRsp* response,
                        ::google::protobuf::Closure* done)override {
        // 组织错误响应
        auto err_handle = [&response, &request](const std::string& err_msg)->void {
            response->set_request_id(request->request_id());
            response->set_success(false);
            response->set_errmsg(err_msg);
            LOG_ERROR("SetUserPhoneNumber 失败: {}", err_msg);
        };
        brpc::ClosureGuard guard(done);

        std::string uid = request->user_id();
        if(uid.empty()) {
            err_handle("用户ID不能为空");
            return;
        }
        std::string phone = request->phone_number();
        if(!phone_valid(phone)) {
            err_handle("手机号不合法");
            return;
        }

        std::string code_id = request->phone_verify_code_id();
        std::string code = request->phone_verify_code();
        // 检查验证码的合法性
        if(!verify_code_valid(code)) {
            err_handle("验证码不合法");
            return;
        }

        //判断用户是否存在
        auto user = _user_table->select_by_id(uid);
        if(!user) {
            err_handle("用户不存在");
            LOG_ERROR(" {}", uid);
            return;
        }

        //比对验证码
        if(code != _redis_codes->code(code_id)) {
            err_handle("验证码不一致");
            LOG_ERROR(" {}", uid);
            return;
        }
        _redis_codes->remove(code_id); // 验证码使用后删除

        // 更新到数据库
        user->set_phone(phone);
        bool success = _user_table->update(user);
        if(!success) {
            err_handle("更新用户手机号到mysql失败");
            LOG_ERROR(" {}", uid);
            return;
        }

        //更新到es
        success = _es_client->appendData(uid, user->user_name(), phone, user->description(), user->avatar_id());
        if(!success) {
            err_handle("更新用户手机号到es失败");
            LOG_ERROR(" {}", uid);
            return;
        }

        //组织响应
        response->set_request_id(request->request_id());
        response->set_success(true);
        LOG_DEBUG("SetUserPhoneNumber 成功: {}", uid);
    }


private:
    UserTable::ptr _user_table;
    ESUser::ptr _es_client;
    Session::ptr _redis_session;
    Status::ptr _redis_status;
    Codes::ptr _redis_codes;    
    DMSClient::ptr _dms_client;
    ServiceManager::ptr _file_service_channel;
    std::string _file_service_name;
};


class UserServer {
public:
    using ptr = std::shared_ptr<UserServer>;

    UserServer (Registry::ptr registry_client,
                Discovery::ptr discovery_client,
                std::shared_ptr<odb::core::database> mysql_client,
                std::shared_ptr<sw::redis::Redis> redis_client,
                std::shared_ptr<elasticlient::Client> es_client,
                std::shared_ptr<brpc::Server> server)
    : _registry_client(registry_client)
    , _discovery_client(discovery_client)
    , _mysql_client(mysql_client)
    , _redis_client(redis_client)
    , _es_client(es_client)
    , _server(server) {}


    void start() {
        LOG_INFO("用户管理服务已启动");
        _server->RunUntilAskedToQuit();
    }

private:
    
    Registry::ptr _registry_client;
    Discovery::ptr _discovery_client;

    std::shared_ptr<odb::core::database> _mysql_client;
    std::shared_ptr<sw::redis::Redis> _redis_client;
    std::shared_ptr<elasticlient::Client> _es_client;

    std::shared_ptr<brpc::Server> _server;
};


class UserServerBuilder { 
public:
    void make_dms_object(const std::string &access_key_id,
        const std::string &access_key_secret) {
        _dms_client = std::make_shared<DMSClient>(access_key_id, access_key_secret);
    }

    void make_reg_object(const std::string &etcd_host, const std::string& service_name, const std::string service_host) {
        _registry_client = std::make_shared<Registry>(etcd_host);
        bool success = _registry_client->registry(service_name, service_host);
        if(!success)
        {
            LOG_ERROR("注册服务到etcd失败");
            return;
        }
        LOG_INFO("注册服务{} - {}到etcd成功", service_name, service_host);
    }


    void make_rpc_object(uint16_t port, int32_t timeout, uint8_t num_threads) {
        logging::LoggingSettings tmp_log;
        tmp_log.logging_dest = logging::LOG_TO_NONE;
        logging::InitLogging(tmp_log);
        _server = std::make_shared<brpc::Server>();
        int ret = _server->AddService(_user_service_impl.get(), brpc::SERVER_DOESNT_OWN_SERVICE);
        if(ret < 0)
        {
            LOG_ERROR("注册服务失败");
            return;
        }
        brpc::ServerOptions options;
        options.idle_timeout_sec = timeout;
        options.num_threads = num_threads;
        ret = _server->Start(port, &options);
        if(ret < 0)
        {
            LOG_ERROR("启动服务器失败");
            abort();  
        }
    }


    void make_discovery_object(const std::string &etcd_host, const std::string &basedir, const std::string &service_name) {
        _file_service_name = basedir + service_name;
        _service_manager = std::make_shared<ServiceManager>();     
        _service_manager->declared(_file_service_name);   
        auto put_cb = std::bind(&ServiceManager::onServiceOnline, _service_manager, std::placeholders::_1, std::placeholders::_2);
        auto del_cb = std::bind(&ServiceManager::onServiceOffline, _service_manager, std::placeholders::_1, std::placeholders::_2);
        _discovery_client = std::make_shared<Discovery>(etcd_host, _file_service_name, put_cb, del_cb);
        if(_discovery_client == nullptr)
        {
            LOG_ERROR("创建服务发现对象失败");
            abort();
        }
        
    }


    void make_mysql_object(
        const std::string &user,
        const std::string &pswd,
        const std::string &host,
        const std::string &db,
        const std::string &cset,
        int port,
        int conn_pool_count) {
        _mysql_client = ODBFactory::create(user, pswd, db, host, port, cset, conn_pool_count);
    }


    void make_redis_object(const std::string& ip, int port, int db, bool keep_alive = true) {
        _redis_client = RedisClientFactory::create(ip, port, db, keep_alive);
    }


    void make_es_object(const std::vector<std::string>& es_addr_list) {
        _es_client = ESClientFactory::create(es_addr_list); 
    }

    void make_user_service_impl() {
        _user_service_impl = std::make_shared<UserServiceImpl>(_mysql_client, _redis_client, _es_client, _dms_client, _service_manager, _file_service_name);
    }
    UserServer::ptr build() {
        if(_user_service_impl == nullptr)
        {
            LOG_ERROR("用户服务实例未创建");
            return nullptr;
        }
        if(_registry_client == nullptr)
        {
            LOG_ERROR("注册中心对象未创建");
            return nullptr;
        }
        if(_server == nullptr)
        {
            LOG_ERROR("RPC服务器对象未创建");
            return nullptr;
        }


        if(_discovery_client == nullptr)
        {
            LOG_ERROR("服务发现对象未创建");
            return nullptr;
        }

        return std::make_shared<UserServer>(_registry_client, _discovery_client, _mysql_client, _redis_client, _es_client, _server);
    }
private:
    std::string _file_service_name;
    UserServiceImpl::ptr _user_service_impl;
    
    Registry::ptr _registry_client;
    Discovery::ptr _discovery_client;
    ServiceManager::ptr _service_manager;

    std::shared_ptr<odb::core::database> _mysql_client;
    std::shared_ptr<sw::redis::Redis> _redis_client;
    std::shared_ptr<elasticlient::Client> _es_client;
    DMSClient::ptr _dms_client;

    std::shared_ptr<brpc::Server> _server;
};    
